﻿#include <QDebug>
#include <math.h>
#include <QDateTime>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonParseError>
#include "TrKlineWidget.h"
#include <spdlog/spdlog.h>
#include <QPainter>
#include <QWheelEvent>

TrKlineWidget::TrKlineWidget(CTrManager *ptr, QString code, WTSKlinePeriod stype) :
  m_strCode(code),
  m_KlinePeriod(stype),
  m_pTrManager(ptr)
{
    initStyle();

    m_Contract = m_pTrManager->TrContract(code.toStdString().c_str());
    m_Commodity = m_pTrManager->TrCommodity(m_Contract.m_strProduct.c_str());

    this->setMouseTracking(true);

    data = new TrDataManager(m_strCode);
    connect(data, SIGNAL(OnDataUpdated()), this, SLOT(OnDataUpdated()));

    m_iNowShowCount = 200;
}

void TrKlineWidget::drawDebugInfo(bool show)
{
    if (show == false)
        return;
    QPainter painter(this);
    QPen pen;
    pen.setColor(QColor(Qt::yellow));
    painter.setPen(pen);
    QString t = QString("Rect: {w} * {h}").replace("{w}", QString::number(m_iWidth)).replace("{h}", QString::number(m_iHeight));
    painter.drawText(5,40, t);
    QString t1 = QString("Datas: %1").arg(data->size());
    painter.drawText(5,60, t1);
    QString t2 = QString("PriceLimit: {h} - {l} = {c}").replace("{h}", QString::number(m_dHeightLine)).replace("{l}", QString::number(m_dLowLine)).replace("{c}", QString::number(m_dHeightLine - m_dLowLine));
    painter.drawText(5,80, t2);
    QString t3 = QString("NowShowCount: %1").arg(m_iNowShowCount);
    painter.drawText(5,100, t3);
    QString t4 = QString("MaxShowCount: %1").arg(m_iMaxShowCount);
    painter.drawText(5,120, t4);



}

void TrKlineWidget::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event)

    drawText();
    drawKline();
    drawGrid();
    drawLastPrice();
    drawDebugInfo(true);
    drawCrosshairs();
}

void TrKlineWidget::drawKline()
{
    QPainter painter(this);
    //painter.setRenderHint(QPainter::Antialiasing);
    R.setRect(0, 25, width()-m_iRightPadding, height()-50);
    painter.drawRect(R);

    m_iWidth = R.width();
    m_iHeight = R.height();
    // 当前屏宽能显示的最多K线数量，每个K线最小占据3个像素
    m_iMaxShowCount = static_cast<int>(m_iWidth/2.5);
    // 上下空余5跳的距离
    int    size = static_cast<int>(data->size());
    m_iNowShowCount = size <= m_iNowShowCount ? size : m_iNowShowCount;
    double prTick = 20 * m_Contract.m_priceTick;

    m_dHeightLine = data->highPrice(m_iNowShowCount, size-m_iNowShowCount) + prTick;
    m_dLowLine = data->lowPrice(m_iNowShowCount, size-m_iNowShowCount) - prTick;

    m_dPriceRange = tf((m_dHeightLine - m_dLowLine) / m_Contract.m_priceTick);

    double xStep = js(static_cast<qreal>(m_iWidth) / m_iNowShowCount);
    qDebug() << xStep;

    m_yScale = static_cast<qreal>(m_iHeight) / m_dPriceRange;

    for (int i = 0; i < m_iNowShowCount; ++i) {
        WTSBarStruct bar = data->getBar(size-m_iNowShowCount+i);
        if(static_cast<int>(bar.open) == 0) break;

        qreal x = i * xStep;
        qreal yHigh = (m_dHeightLine - bar.high) * m_yScale / m_Contract.m_priceTick;
        qreal yLow = (m_dHeightLine - bar.low) * m_yScale / m_Contract.m_priceTick;
        qreal yOpen = (m_dHeightLine - bar.open) * m_yScale / m_Contract.m_priceTick;
        qreal yClose = (m_dHeightLine - bar.close) * m_yScale / m_Contract.m_priceTick;

        if (bar.open < bar.close) {
            painter.setPen(PenRed);
            painter.setBrush(QColor(242, 54, 69));
            PenRed.setWidthF(1);
        } else {
            painter.setPen(PenGreen);
            painter.setBrush(QColor(8, 153, 129));
            PenGreen.setWidthF(1);
        }

        //qDebug() << xStep;

        if (xStep <= 4)
        {

            qreal rectWidth = 1;
            qreal gapWidth = 0.5;

            QRectF rect(x + gapWidth, yHigh, rectWidth, yLow - yOpen);
            painter.drawLine(QLineF(x+gapWidth, yHigh, x+gapWidth, yLow));
            //painter.drawRect(rect);
        } else if(xStep > 10) {

            qreal rectWidth = js(xStep);
            qreal gapWidth = rectWidth * 0.3;

            QRectF rect(x+gapWidth, yOpen, rectWidth-gapWidth, yClose - yOpen);

            painter.drawRect(rect);
            qreal lineX = x + rectWidth * 0.5 + gapWidth * 0.5;
            painter.setBrush(QColor(8, 153, 129));
            QLineF linef(lineX, yHigh, lineX, yLow);
            painter.drawLine(linef);

        } else {

            qreal rectWidth = js(xStep);
            qreal gapWidth = rectWidth * 0.5;

            QRectF rect(x+gapWidth, yOpen, rectWidth-gapWidth, yClose - yOpen);

            painter.drawRect(rect);
            qreal lineX = x + rectWidth * 0.5 + gapWidth * 0.5;
            painter.setBrush(QColor(8, 153, 129));
            QLineF linef(lineX, yHigh, lineX, yLow);
            painter.drawLine(linef);

        }
    }
}

void TrKlineWidget::wheelEvent(QWheelEvent *event)
{
    QPoint wheel = event->angleDelta();
    int step = 30;

    if(wheel.ry() > 0){
        if(m_iNowShowCount+step >= m_iMaxShowCount)
        {
            m_iNowShowCount = m_iMaxShowCount;
        } else {
            m_iNowShowCount = m_iNowShowCount + step;
        }
    } else {
        if(m_iNowShowCount-step < 10) return;
        m_iNowShowCount = m_iNowShowCount - step;
    }

    //qDebug() << m_iNowShowCount << m_iMaxShowCount;
    QWidget::wheelEvent(event);
    update();

}

void TrKlineWidget::initStyle()
{
    QPalette palette;
    setAutoFillBackground(true);
    palette.setColor(QPalette::Window, QColor(21, 25, 36)); // 设置背景色为蓝色
    setPalette(palette);

    PenGreen.setColor(QColor(8, 153, 129));
    PenRed.setColor(QColor(242, 54, 69));
    PenYellow.setColor(Qt::yellow);
    PenGrey.setColor(QColor(34, 38, 49));
}

void TrKlineWidget::drawGrid()
{
    QPainter painter(this);
    QPen pen;
    pen.setColor(QColor(34, 38, 49));
    painter.setPen(pen);
    painter.drawLine(width()-m_iRightPadding+10,0,width()-m_iRightPadding+10,m_iHeight);
}

void TrKlineWidget::drawText()
{
    QPainter painter(this);
    QPen pen;
    pen.setColor(Qt::yellow);
    painter.setPen(pen);
    QString title = QString::fromLocal8Bit(m_Contract.m_strName.c_str());
    title.append(" ").append(getPeriodName(m_KlinePeriod));
    painter.drawText(5, 15, title);
}

QString TrKlineWidget::getPeriodName(WTSKlinePeriod stype)
{
    QString name;
    switch (stype) {
    case KP_Tick:
        name.append(QString::fromLocal8Bit("分时"));
        break;
    case KP_DAY:
        name.append(QString::fromLocal8Bit("日K"));
        break;
    case KP_Minute1:
        name.append(QString::fromLocal8Bit("1分钟"));
        break;
    case KP_Minute5:
        name.append(QString::fromLocal8Bit("5分钟"));
        break;
    case KP_Minute15:
        name.append(QString::fromLocal8Bit("15分钟"));
        break;
    case KP_Minute60:
        name.append(QString::fromLocal8Bit("1小时"));
        break;
    case KP_Week:
        name.append(QString::fromLocal8Bit("周线"));
        break;
    case KP_Month:
        name.append(QString::fromLocal8Bit("月线"));
        break;
    }
    return name;
}

QString TrKlineWidget::getCode()
{
    return m_strCode;
}
void TrKlineWidget::drawLastPrice()
{
    QPainter painter(this);
    QPen xxPen;
    xxPen.setStyle(Qt::DotLine);

    WTSBarStruct bar = data->getBar(static_cast<int>(data->size()-1));
    if(static_cast<int>(bar.open) == 0) return;
    double lastPrice = data->lastPrice();
    if(bar.open > lastPrice){
        painter.setPen(PenGreen);
        painter.setBrush(QColor(8, 153, 129));
        xxPen.setColor(QColor(8, 153, 129));
    } else if(bar.open < lastPrice) {
        painter.setPen(PenRed);
        painter.setBrush(QColor(242, 54, 69));
        xxPen.setColor(QColor(242, 54, 69));
    } else {
        painter.setPen(PenGrey);
        painter.setBrush(QColor(34, 38, 49));
        xxPen.setColor(QColor(34, 38, 49));
    }

    qreal yClose = (m_dHeightLine - lastPrice) * m_yScale / m_Contract.m_priceTick;

    QRectF rect(width()-m_iRightPadding+12, static_cast<int>(yClose-16), width()-m_iRightPadding, 32);
    painter.drawRect(rect);

    painter.setPen(xxPen);
    QLineF line(0, yClose, width()-m_iRightPadding+10, yClose);
    painter.drawLine(line);

    QPen wPen;
    wPen.setColor(Qt::white);
    painter.setPen(wPen);
    rect.setX(rect.x()+5);
    rect.setY(rect.y()+4);
    painter.drawText(rect, 0, QString::number(lastPrice));
    rect.setY(rect.y()+14);
    painter.drawText(rect, 0, QDateTime::fromTime_t(data->lastUpdateTime()).toString("hh:mm:ss"));

}

void TrKlineWidget::mouseMoveEvent(QMouseEvent* ev)
{
    if (m_bShowCrosshairs == false) return;
    if(m_bShowCrosshairs)
    {
        m_mousePoint = ev->pos();
        update();
    }
}

void TrKlineWidget::drawCrosshairs()
{
    if (m_bShowCrosshairs == false) return;
    QPainter painter(this);
    QPen xxPen;
    xxPen.setColor(Qt::white);
    xxPen.setStyle(Qt::DashLine);
    //xxPen.setStyle(Qt::SolidLine);
    //xxPen.setWidthF(0.5);
    painter.setPen(xxPen);

    painter.drawLine(QLineF(0, m_mousePoint.ry(), width(), m_mousePoint.ry()));
    painter.drawLine(QLineF(m_mousePoint.rx(), 0, m_mousePoint.rx(), height()));
}

void TrKlineWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event)
    m_mousePoint = event->pos();
    m_bShowCrosshairs = m_bShowCrosshairs == false ? true : false;
    m_bShowCrosshairs == false ? setCursor(Qt::ArrowCursor) : setCursor(Qt::BlankCursor);
    update();
}

double TrKlineWidget::tf(double c)
{
    char buffer[50];
    std::sprintf(buffer, "%.2f", c);
    return atof(buffer);
}

double TrKlineWidget::js(double c)
{
    int t = static_cast<int>(tf(c)*10);
    return tf(t % 2 == 0 ? c : c - 0.1);
}

void TrKlineWidget::OnDataUpdated()
{
    repaint();
}
